package com.cpp.server.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cpp.common.constant.ExamInfoConstant;
import com.cpp.common.constant.redis.OperationConstant;
import com.cpp.common.constant.redis.RedisConstant;
import com.cpp.common.enums.*;
import com.cpp.common.exception.BaseException;
import com.cpp.common.properties.PageProperties;
import com.cpp.common.result.PageResult;
import com.cpp.pojo.dto.exam.AnswerDTO;
import com.cpp.pojo.dto.exam.ExamCreateDTO;
import com.cpp.pojo.dto.exam.ExamPageDTO;
import com.cpp.pojo.dto.exam.ExamSubmitDTO;
import com.cpp.pojo.pojo.*;

import com.cpp.pojo.pojo.ExamPageVO;
import com.cpp.pojo.vo.exam.ExamPaperVO;
import com.cpp.pojo.vo.exam.ExamVO;
import com.cpp.pojo.vo.question.QuestionCreateConfirmVO;
import com.cpp.pojo.vo.question.QuestionExamVO;
import com.cpp.pojo.vo.summary.ExamReport;
import com.cpp.server.aspect.annotation.StartTimeRecord;
import com.cpp.server.aspect.annotation.UserRole;
import com.cpp.server.context.UserHolder;
import com.cpp.server.mapper.*;
import com.cpp.server.service.ExamService;
import com.cpp.server.websocket.MyWebSocketHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 34044
 * @description 针对表【exam(考试表)】的数据库操作Service实现
 * @createDate 2025-05-12 10:50:05
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ExamServiceImpl extends ServiceImpl<ExamMapper, Exam> implements ExamService {

    private final QuestionMapper questionMapper;
    private final StudentCourseMapper studentCourseMapper;
    private final ExamRecordMapper examRecordMapper;
    private final AnswerRecordMapper answerRecordMapper;
    private final KnowledgeMapper knowledgeMapper;
    private final UserMapper userMapper;
    private final CourseMapper courseMapper;

    private final ChatClient gnerateQuestionChatClient;
    private final ChatClient markPaperClient;
    private final ChatClient summaryExamClient;

    private final StringRedisTemplate stringRedisTemplate;

    private final PageProperties pageProperties;


    @Override
    @UserRole(roles = {UserRoleEnum.TEACHER})
    @StartTimeRecord(value = OperationConstant.generatePractice)
    public void createExam(ExamCreateDTO examCreateDTO) {
        //拿到当前用户
        User user = UserHolder.getCurrentUser();
        //准备判断数据
        LocalDateTime now = LocalDateTime.now();
        //判断考试标题是否超过100个字符
        if (examCreateDTO.getExamTitle().length() > 100) {
            throw new BaseException(ExamInfoConstant.EXAM_TITLE_ERROR);
        }
        //判断考试描述是否超过500个字符
        if (examCreateDTO.getExamDetail().length() > 500) {
            throw new BaseException(ExamInfoConstant.EXAM_DESC_ERROR);
        }
        //考试开始时间不能早于现在
//        if (now.isAfter(examCreateDTO.getStartTime())) {
//            throw new BaseException(ExamInfoConstant.EXAM_START_TIME_ERROR);
//        }
        //判断考试开始时间是否在结束时间之后
        if (examCreateDTO.getStartTime().isAfter(examCreateDTO.getEndTime())) {
            throw new BaseException(ExamInfoConstant.EXAM_START_TIME_AFTER_END_TIME);
        }
        //考试时长不能超过三小时
        if (examCreateDTO.getTotalTime() > 180) {
            throw new BaseException(ExamInfoConstant.EXAM_DURATION_ERROR);
        }
        //考试开始时间+考试总时长<考试结束时间
        if (examCreateDTO.getStartTime().plusMinutes(examCreateDTO.getTotalTime()).isAfter(examCreateDTO.getEndTime())) {
            throw new BaseException(ExamInfoConstant.EXAM_START_TIME_AFTER_END_TIME_ERROR);
        }

        //补充数据
        Exam exam = new Exam();
        BeanUtils.copyProperties(examCreateDTO, exam);
        exam.setUserId(user.getId());

        //操作数据库
        save(exam);
        CompletableFuture.runAsync(() -> {
            List<Question> questions = new ArrayList<>();
            //异步调用
            while (true) {
                Exam check = check(questions, exam);
                if (check == null) {
                    break;
                }
                questions = generate(check);
            }
            //封装数据
            List<QuestionCreateConfirmVO.QuestionVO> questionExamVOS = new ArrayList<>();
            for (Question question : questions) {
                QuestionCreateConfirmVO.QuestionVO questionVO = QuestionCreateConfirmVO.QuestionVO.builder()
                        .questionId(question.getId())
                        .type(question.getType())
                        .content(question.getContent())
                        .difficulty(question.getDifficulty())
                        .answer(question.getAnswer())
                        .analysis(question.getAnalysis())
                        .score(question.getScore())
                        .build();
                questionExamVOS.add(questionVO);
            }

            QuestionCreateConfirmVO confirmVO = QuestionCreateConfirmVO.builder()
                    .questions(questionExamVOS)
                    .examId(exam.getId())
                    .build();
            //websocket推送
            log.info("confirmVO{}",confirmVO);
            MyWebSocketHandler.sendMessageToUser(JSON.toJSONString(confirmVO));
        });

//        List<QuestionCreateConfirmVO.QuestionVO> questionVOS = new ArrayList<>();
//        for (Question question : questions) {
//            questionVOS.add(QuestionCreateConfirmVO.QuestionVO.builder()
//                    .questionId(question.getId())
//                    .type(question.getType())
//                    .content(question.getContent())
//                    .difficulty(question.getDifficulty())
//                    .answer(question.getAnswer())
//                    .analysis(question.getAnalysis())
//                    .score(question.getScore())
//                    .build());
//        }

//        log.info("exam:{}",exam);
//        return QuestionCreateConfirmVO.builder()
//                .questions(questionVOS)
//                .examId(exam.getId())
//                .build();
    }

    private List<Question> generate(Exam exam) {
        String prompt = "";
        if (exam.getType1Count() != 0) {
            prompt += "生成" + QuestionType.OPEN_QUESTION.getName() + exam.getType1Count() + "道";
        }
        if (exam.getType2Count() != 0) {
            prompt += "生成" + QuestionType.SHORT_ANSWER.getName() + exam.getType2Count() + "道";
        }
        if (exam.getType3Count() != 0) {
            prompt += "生成" + QuestionType.SINGLE_CHOICE.getName() + exam.getType3Count() + "道";
        }
        if (exam.getType4Count() != 0) {
            prompt += "生成" + QuestionType.MULTIPLE_CHOICE.getName() + exam.getType4Count() + "道";
        }
        //调用ai生成题目
//        0实训练习1开放题/2简答题/3单选题/4多选题
        String content = gnerateQuestionChatClient.prompt()
                .user(
                        "获取知识点信息，把生成的题目保存到数据库" +
                                "获取知识点信息，把生成的题目保存到数据库" +
                                prompt +
                                "考试所有的信息：" + exam.getExamTitle() + exam.getExamTitle() + exam.getId() + exam.getUserId() +
                                "课程id" + exam.getCourseId())
                .call()
                .content();
        //查询ai生成的题目返回
        log.info("ai生成题目：{}", content);
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Question::getExamId, exam.getId());
        List<Question> questions = questionMapper.selectList(queryWrapper);
        return questions;
    }

    private Exam check(List<Question> questions, Exam exam) {
        int type1 = 0;
        int type2 = 0;
        int type3 = 0;
        int type4 = 0;
        Exam useExam = BeanUtil.copyProperties(exam, Exam.class);
        for (Question question : questions) {
            switch (question.getType()) {
                case 1:
                    type1++;
                    break;
                case 2:
                    type2++;
                    break;
                case 3:
                    type3++;
                    break;
                case 4:
                    type4++;
                    break;
                default:
                    break;
            }
        }
        //判断某个题目是不是生成完毕,条件是统计出的题目数等于实际题目数
        if (type1 == exam.getType1Count() && type2 == exam.getType2Count() && type3 == exam.getType3Count() && type4 == exam.getType4Count()) {
            return null;
        }
        log.info("目前题型type1:{},type2:{},type3:{},type4:{}", type1, type2, type3, type4);
        //如果某种题目统计值大于它的生成值则删除
        if (type1 > exam.getType1Count()) {
            LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Question::getExamId, useExam.getId());
            queryWrapper.eq(Question::getType, 1);
            Integer num1 = type1 - useExam.getType1Count();
            queryWrapper.last("LIMIT " + num1);
            questionMapper.delete(queryWrapper);
            log.info("删除多余的题目1{}", num1);
        }
        if (type2 > exam.getType2Count()) {
            LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Question::getExamId, useExam.getId());
            queryWrapper.eq(Question::getType, 2);
            Integer num2 = type2 - useExam.getType2Count();
            queryWrapper.last("LIMIT " + num2);
            questionMapper.delete(queryWrapper);
            log.info("删除多余的题目2{}", num2);
        }
        if (type3 > exam.getType3Count()) {
            LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Question::getExamId, useExam.getId());
            queryWrapper.eq(Question::getType, 3);
            Integer num3 = type3 - useExam.getType3Count();
            queryWrapper.last("LIMIT " + num3);
            questionMapper.delete(queryWrapper);
            log.info("删除多余的题目3{}", num3);
        }
        if (type4 > exam.getType4Count()) {
            LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Question::getExamId, useExam.getId());
            queryWrapper.eq(Question::getType, 4);
            Integer num4 = type4 - useExam.getType4Count();
            queryWrapper.last("LIMIT " + num4);
            questionMapper.delete(queryWrapper);
            log.info("删除多余的题目4{}", num4);
        }
        int newType1 = exam.getType1Count() - type1;
        int newType2 = exam.getType2Count() - type2;
        int newType3 = exam.getType3Count() - type3;
        int newType4 = exam.getType4Count() - type4;

        if (newType1 < 0) {
            newType1 = 0;
        }
        if (newType2 < 0) {
            newType2 = 0;
        }
        if (newType3 < 0) {
            newType3 = 0;
        }
        if (newType4 < 0) {
            newType4 = 0;
        }
        if (newType1 == 0 && newType2 == 0 && newType3 == 0 && newType4 == 0) {
            return null;
        }
        log.info("确实题型type1:{},type2:{},type3:{},type4:{}", newType1, newType2, newType3, newType4);
        return Exam.builder()
                .type1Count(newType1)
                .type2Count(newType2)
                .type3Count(newType3)
                .type4Count(newType4)
                .courseId(exam.getCourseId())
                .id(exam.getId())
                .build();

    }

    //查询考试,自己选的课程的考试
    @Override
    @UserRole(roles = {UserRoleEnum.STUDENT, UserRoleEnum.TEACHER})
    public PageResult pageExam(ExamPageDTO examPageDTO) {
        User currentUser = UserHolder.getCurrentUser();

        //分页数据准备
        Integer page = examPageDTO.getPageNum();
        Integer pageSize = examPageDTO.getPageSize();

        if (page == null || page <= 0) {
            page = pageProperties.getPage();
        }
        if (pageSize == null || pageSize <= 0) {
            pageSize = pageProperties.getPageSize();
        }
        //判断是学生还是老师
        if (currentUser.getRole().equals(UserRoleEnum.STUDENT.getRole())) {
            //学生返回所有他选课的考试
            Page<ExamPageVO> pageExam = pageExamForStudent(page, pageSize);
            List<ExamPageVO> exams = pageExam.getRecords();
            List<ExamVO> examVOs = new ArrayList<>();
            for (ExamPageVO exam : exams) {
                ExamVO examVO = ExamVO.builder()
                        .examId(exam.getExamId())
                        .examTitle(exam.getExamTitle())
                        .examDetail(exam.getExamDetail())
                        .submitStatus(exam.getSubmitStatus())
                        .statusName(ExamStatus.getMessageByCode(exam.getStatus()))
                        .attemptLimit(exam.getAttemptLimit())
                        .questionCount(exam.getQuestionCount())
                        .startTime(exam.getStartTime())
                        .endTime(exam.getEndTime())
                        .totalTime(exam.getTotalTime())
                        .build();
                examVOs.add(examVO);
            }
            return new PageResult(pageExam.getTotal(), examVOs);
        } else if (currentUser.getRole().equals(UserRoleEnum.TEACHER.getRole())) {
            //老师返回所有他创建的考试
            Page<Exam> pageExam = pageExamForTeacher(page, pageSize);
            List<Exam> exams = pageExam.getRecords();
            List<ExamVO> examVOs = new ArrayList<>();
            for (Exam exam : exams) {
                ExamVO examVO = ExamVO.builder()
                        .examId(exam.getId())
                        .examTitle(exam.getExamTitle())
                        .examDetail(exam.getExamDetail())
                        .statusName(ExamStatus.getMessageByCode(exam.getStatus()))
                        .attemptLimit(exam.getAttemptLimit())
                        .questionCount(exam.getQuestionCount())
                        .startTime(exam.getStartTime())
                        .endTime(exam.getEndTime())
                        .totalTime(exam.getTotalTime())
                        .build();
                examVOs.add(examVO);
            }
            return new PageResult(pageExam.getTotal(), examVOs);
        }
        //报错
        throw new BaseException("用户权限错误");
    }




    private Page<ExamPageVO> pageExamForStudent(Integer page, Integer pageSize) {
        User currentUser = UserHolder.getCurrentUser();

        LambdaQueryWrapper<StudentCourse> scWrapper = new LambdaQueryWrapper<>();
        scWrapper.eq(StudentCourse::getStudentId, currentUser.getId());
        List<StudentCourse> courses = studentCourseMapper.selectList(scWrapper);

        //拿到所有课程id
        List<Long> courseIds = courses.stream().map(StudentCourse::getCourseId).toList();

        if (courseIds.isEmpty()) {
            return new Page<ExamPageVO>();
        }

        //分页查询考试
        Page<Exam> pageQuery = new Page<>(page, pageSize);
        LambdaQueryWrapper<Exam> examWrapper = new LambdaQueryWrapper<>();
        examWrapper.eq(Exam::getStatus, ExamStatus.PUBLISHED.getCode());
        examWrapper.in(Exam::getCourseId, courseIds);
        examWrapper.orderByDesc(Exam::getId);
        //考试结束时间晚于现在
//        examWrapper.ge(Exam::getEndTime, LocalDateTime.now());
        Page<Exam> page1 = page(pageQuery, examWrapper);
        //用循环转换格式
        List<ExamPageVO> examPageVOS = new ArrayList<>();
        for (Exam exam : page1.getRecords()) {
            //查询对应考试记录
            LambdaQueryWrapper<ExamRecord> recordWrapper = new LambdaQueryWrapper<>();
            recordWrapper.eq(ExamRecord::getExamId, exam.getId());
            recordWrapper.eq(ExamRecord::getUserId, currentUser.getId());
            List<ExamRecord> examRecord = examRecordMapper.selectList(recordWrapper);

            Integer submitStatus = examRecord.size() > 0 ? 1 : 0;

            ExamPageVO examPageVO = ExamPageVO.builder()
                    .examId(exam.getId())
                    .examTitle(exam.getExamTitle())
                    .examDetail(exam.getExamDetail())
                    .status(exam.getStatus())
                    .submitStatus(submitStatus)
                    .attemptLimit(exam.getAttemptLimit())
                    .questionCount(exam.getQuestionCount())
                    .startTime(exam.getStartTime())
                    .endTime(exam.getEndTime())
                    .totalTime(exam.getTotalTime())
                    .build();

            examPageVOS.add(examPageVO);
        }
        Page<ExamPageVO> pageVOPage = new Page<>();
        pageVOPage.setTotal(page1.getTotal());
        pageVOPage.setRecords(examPageVOS);

        return pageVOPage;
    }

    private Page<Exam> pageExamForTeacher(Integer page, Integer pageSize) {
        User currentUser = UserHolder.getCurrentUser();

        //分页查询考试
        Page<Exam> pageQuery = new Page<>(page, pageSize);
        LambdaQueryWrapper<Exam> examWrapper = new LambdaQueryWrapper<>();
        examWrapper.orderByDesc(Exam::getId);
        examWrapper.eq(Exam::getUserId, currentUser.getId());
        return page(pageQuery, examWrapper);
    }

    @Override
    @UserRole(roles = {UserRoleEnum.STUDENT})
    public ExamPaperVO startExam(Long examId) {
        //业务判断
        User currentUser = UserHolder.getCurrentUser();
        Exam exam = getById(examId);
        log.info("开始考试{}", exam);
        if (exam.getStatus().equals(ExamStatus.UNPUBLISHED.getCode())) {
            throw new BaseException("该考试还未发布");
        }

        //根据考试id查询考试记录
        LambdaQueryWrapper<ExamRecord> erWrapper = new LambdaQueryWrapper<>();
        erWrapper.eq(ExamRecord::getExamId, examId);
        erWrapper.eq(ExamRecord::getUserId, currentUser.getId());
        List<ExamRecord> examRecords = examRecordMapper.selectList(erWrapper);

        //查出来为数列，但业务逻辑为只有一条
        Integer attemptNum = 0;
        //判断是不是第一次考试
        if (!examRecords.isEmpty()) {
            ExamRecord examRecord = examRecords.get(0);
            //判断是不是正在考试
            if (examRecord.getStatus().equals(ExamRecordStatus.PROCESSING.getCode())) {
                //查询题目
                List<QuestionExamVO> examQuestion = getExamQuestion(examId);
                //题型数据处理
                ExamPaperVO examPaperVO = questionTypeHandler(examQuestion);
                //返回数据
                return examPaperVO;
            }
            //判断考试次数
            if (examRecord.getAttemptNum() >= exam.getAttemptLimit()) {
                throw new BaseException("考试次数已达上限");
            }
            attemptNum = examRecord.getAttemptNum();
        }
        //判断考试时间
        if (exam.getStartTime().isAfter(LocalDateTime.now())) {
            throw new BaseException("你来的真早，考试还未开始。");
        }
        //判断考试时间
        if (exam.getEndTime().isBefore(LocalDateTime.now())) {
            throw new BaseException("考试已结束，下次记得早点来哦。");
        }

        //开始考试业务
        //生成考试记录
        ExamRecord build = ExamRecord.builder()
                .attemptNum(attemptNum + 1)
                .status(ExamRecordStatus.PROCESSING.getCode())
                .examId(examId)
                .userId(currentUser.getId())
                .build();
        examRecordMapper.insert(build);
        //查询题目
        List<QuestionExamVO> examQuestion = getExamQuestion(examId);
        //题型数据处理
        ExamPaperVO examPaperVO = questionTypeHandler(examQuestion);
        //返回数据
        return examPaperVO;
    }

    private ExamPaperVO questionTypeHandler(List<QuestionExamVO> examQuestion) {

        List<QuestionExamVO> openQuestions = new ArrayList<>();
        List<QuestionExamVO> shortQuestions = new ArrayList<>();
        List<QuestionExamVO> singleQuestions = new ArrayList<>();
        List<QuestionExamVO> multipleQuestions = new ArrayList<>();
        //    1开放题/2简答题/3单选题/4多选题
        for (QuestionExamVO questionExamVO : examQuestion) {
            switch (questionExamVO.getType()) {
                case 1:
                    openQuestions.add(questionExamVO);
                    break;
                case 2:
                    shortQuestions.add(questionExamVO);
                    break;
                case 3:
                    singleQuestions.add(questionExamVO);
                    break;
                case 4:
                    multipleQuestions.add(questionExamVO);
                    break;
            }
        }
        return ExamPaperVO.builder()
                .openQuestions(openQuestions)
                .shortQuestions(shortQuestions)
                .singleQuestions(singleQuestions)
                .multipleQuestions(multipleQuestions)
                .build();
    }

    /**
     * 老师查询考试接口
     *
     * @param examId
     * @return
     */

    @Override
    @UserRole(roles = {UserRoleEnum.TEACHER})
    public QuestionCreateConfirmVO getExamQuestionConfirm(Long examId) {
        //权限校验
        Exam exam = getById(examId);
        if (exam.getUserId() != UserHolder.getCurrentUser().getId()) {
            throw new BaseException("你没有权限");
        }
        //查询考试题目
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Question::getExamId, examId);
        List<Question> questions = questionMapper.selectList(queryWrapper);

        //封装数据
        List<QuestionCreateConfirmVO.QuestionVO> questionExamVOS = new ArrayList<>();
        for (Question question : questions) {
            QuestionCreateConfirmVO.QuestionVO questionVO = QuestionCreateConfirmVO.QuestionVO.builder()
                    .questionId(question.getId())
                    .type(question.getType())
                    .content(question.getContent())
                    .difficulty(question.getDifficulty())
                    .answer(question.getAnswer())
                    .analysis(question.getAnalysis())
                    .score(question.getScore())
                    .build();
            questionExamVOS.add(questionVO);
        }
        QuestionCreateConfirmVO questionCreateConfirmVO = QuestionCreateConfirmVO.builder()
                .examId(examId)
                .questions(questionExamVOS)
                .build();
        return questionCreateConfirmVO;
    }

    @Override
    @UserRole(roles = {UserRoleEnum.TEACHER})
    public QuestionCreateConfirmVO getExamQuestionNoConfirm() {
        User currentUser = UserHolder.getCurrentUser();
        LambdaQueryWrapper<Exam> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Exam::getStatus, ExamStatus.UNPUBLISHED.getCode());
        queryWrapper.eq(Exam::getUserId, currentUser.getId());
        queryWrapper.orderByDesc(Exam::getId);
        //用列表取最新的一场考试，防止以前创建的考试的数据污染
        List<Exam> exams = list(queryWrapper);
        if (exams.size() == 0) {
            throw new BaseException("没有未确认的考试哦，请先创建考试");
        }
        return getExamQuestionConfirm(exams.get(0).getId());
    }

    private List<QuestionExamVO> getExamQuestion(Long examId) {
        //查询考试题目
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Question::getExamId, examId);
        List<Question> questions = questionMapper.selectList(queryWrapper);

        //数据转换Question-》QuestionVO
        List<QuestionExamVO> questionExamVOS = new ArrayList<>();
        for (Question question : questions) {
            Integer type = question.getType();
            if (type.equals(QuestionType.SINGLE_CHOICE.getType()) || type.equals(QuestionType.MULTIPLE_CHOICE.getType())) {
                QuestionExamVO questionExamVO = QuestionExamVO.builder()
                        .questionId(question.getId())
                        .type(question.getType())
                        .typeName(QuestionType.getType(question.getType()).getName())
                        .content(question.getContent())
                        .option(question.getAnswer())
                        .score(question.getScore())
                        .build();
                questionExamVOS.add(questionExamVO);
            } else {
                QuestionExamVO questionExamVO = QuestionExamVO.builder()
                        .questionId(question.getId())
                        .type(question.getType())
                        .typeName(QuestionType.getType(question.getType()).getName())
                        .content(question.getContent())
                        .score(question.getScore())
                        .build();
                questionExamVOS.add(questionExamVO);
            }
        }
        return questionExamVOS;
    }

    //提交考试
    @Override
    @UserRole(roles = {UserRoleEnum.STUDENT})
    public void submitExam(ExamSubmitDTO examSubmitDTO) {
        //业务判断
        User currentUser = UserHolder.getCurrentUser();
        Exam exam = getById(examSubmitDTO.getExamId());

        //查询考试记录
        LambdaQueryWrapper<ExamRecord> erWrapper = new LambdaQueryWrapper<>();
        erWrapper.eq(ExamRecord::getExamId, examSubmitDTO.getExamId());
        erWrapper.eq(ExamRecord::getUserId, currentUser.getId());
        List<ExamRecord> examRecords = examRecordMapper.selectList(erWrapper);
        //根据id倒序排序，拿到最新的考试记录
        ExamRecord examRecord = examRecords.get(0);

        if (examRecord.getStatus().equals(ExamRecordStatus.FINISHED.getCode())) {
            throw new BaseException("考试已结束");
        }

        //获取答案和题目数据
        LambdaQueryWrapper<Question> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Question::getExamId, exam.getId());
        List<Question> questions = questionMapper.selectList(queryWrapper);
        List<AnswerDTO> answers = examSubmitDTO.getAnswers();

        // 构建 questionId 到 Question 的映射
        Map<Long, Question> questionMap = questions.stream()
                .collect(Collectors.toMap(Question::getId, Function.identity()));

        //错题集合
        List<Question> questionError = new ArrayList<>();
        //正确集合
        List<Question> questionRight = new ArrayList<>();

        //校验答案,计算总分
        Integer totalScore = 0;
        for (AnswerDTO answer : answers) {
            Question question = questionMap.get(answer.getQuestionId());
            //开放题
            if (question.getType().equals(QuestionType.OPEN_QUESTION.getType())) {
                Double scoreRate = judgeRightForOpenAndShort(question, answer);
                totalScore += (int) (scoreRate * question.getScore());
                log.info("开放题：{}", scoreRate);
                if (scoreRate < 0.6) {
                    questionError.add(question);
                } else {
                    questionRight.add(question);
                }
            }
            //简答题
            else if (question.getType().equals(QuestionType.SHORT_ANSWER.getType())) {
                Double scoreRate = judgeRightForOpenAndShort(question, answer);
                totalScore += (int) (scoreRate * question.getScore());
                log.info("简答题：{}", scoreRate);
                if (scoreRate < 0.6) {
                    questionError.add(question);
                } else {
                    questionRight.add(question);
                }
            }
            //单选题
            else if (question.getType().equals(QuestionType.SINGLE_CHOICE.getType())) {
                if (judgeRightForSingle(question, answer)) {
                    totalScore += question.getScore();
                    questionRight.add(question);
                } else {
                    questionError.add(question);
                }
            }
            //多选题
            else if (question.getType().equals(QuestionType.MULTIPLE_CHOICE.getType())) {
                if (judgeRightForMultiple(question, answer)) {
                    totalScore += question.getScore();
                    questionRight.add(question);
                } else {
                    questionError.add(question);
                }
            }
        }
        log.info("总分：{}", totalScore);

        Course course = courseMapper.selectById(exam.getCourseId());

        List<AnswerRecord> answerRecords = new ArrayList<>();
        //简历错题答案与questionId的map关系
        Map<Long, String> answerMap = answers.stream().collect(Collectors.toMap(AnswerDTO::getQuestionId, AnswerDTO::getAnswer));
        //存储错题
        for (Question question : questionError) {
            AnswerRecord error = AnswerRecord.builder()
                    .questionId(question.getId())
                    .userId(currentUser.getId())
                    .courseId(question.getCourseId())
                    .examId(question.getExamId())
                    .type(question.getType())
                    .content(question.getContent())
                    .difficulty(question.getDifficulty())
                    .knowledgeIds(question.getKnowledgeIds())
                    .answer(question.getAnswer())
                    .analysis(question.getAnalysis())
                    .score(question.getScore())
                    .status(AnswerStatus.ERROR.getStatus())
                    .subjectId(course.getSubjectId())
                    .userAnswer(answerMap.get(question.getId()))
                    .build();
            answerRecords.add(error);
        }
        answerRecordMapper.insert(answerRecords);

        //保存正确题目
        for (Question question : questionRight) {
            AnswerRecord right = AnswerRecord.builder()
                    .questionId(question.getId())
                    .userId(currentUser.getId())
                    .courseId(question.getCourseId())
                    .examId(question.getExamId())
                    .type(question.getType())
                    .content(question.getContent())
                    .difficulty(question.getDifficulty())
                    .knowledgeIds(question.getKnowledgeIds())
                    .answer(question.getAnswer())
                    .analysis(question.getAnalysis())
                    .score(question.getScore())
                    .status(AnswerStatus.RIGHT.getStatus())
                    .userAnswer(answerMap.get(question.getId()))
                    .subjectId(course.getSubjectId())
                    .build();
            answerRecords.add(right);
        }
        answerRecordMapper.updateById(answerRecords);


        examRecord.setTotalScore(totalScore);
        examRecord.setSubmitTime(LocalDateTime.now());
        examRecord.setStatus("1");
        //更新记录
        examRecordMapper.updateById(examRecord);
    }

    public boolean judgeRightForMultiple(Question question, AnswerDTO answer) {
        try {
            //json转java
            String answerJson = question.getAnswer();
            AnswerOption answerOption = JSON.parseObject(answerJson, AnswerOption.class);
            List<Integer> rightAnswer = answerOption.getRightAnswer();
            String[] split = answer.getAnswer().split(",");
            //把String[]转为List<Integer>
            List<Integer> userAnswer = Arrays.stream(split)
                    .map(Integer::parseInt)
                    .toList();
            //比较数列内容的差异
            return userAnswer.containsAll(rightAnswer) && rightAnswer.containsAll(userAnswer);
        } catch (Exception e) {
            return false;
        }
    }

    public boolean judgeRightForSingle(Question question, AnswerDTO answer) {
        try {
            //json转java
            String answerJson = question.getAnswer();
            AnswerOption answerOption = JSON.parseObject(answerJson, AnswerOption.class);
            //比较正确答案和学生答案
            Integer rightAnswer = answerOption.getRightAnswer().get(0);
            boolean isRight = answer.getAnswer().equals(String.valueOf(rightAnswer));
            return isRight;
        } catch (Exception e) {
            return false;
        }
    }

    public Double judgeRightForOpenAndShort(Question question, AnswerDTO answer) {
        String content = markPaperClient.prompt("只输出小数数字，不用文本")
                .user("题目内容：" + question.getContent() +
                        ",标准答案(如果没有标准答案，按照题目内容推测答案给分)：" + question.getAnswer() +
                        "，用户答案：" + answer)
                .call()
                .content();
        Double scoreRate = Double.valueOf(content);
        return scoreRate;
    }


    @Override
    @UserRole(roles = {UserRoleEnum.STUDENT})
    public Integer getExamScore(Long examId) {
        User currentUser = UserHolder.getCurrentUser();

        LambdaQueryWrapper<ExamRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ExamRecord::getUserId, currentUser.getId());
        queryWrapper.eq(ExamRecord::getExamId, examId);
        //取历史最高分
        queryWrapper.orderByDesc(ExamRecord::getTotalScore);
        List<ExamRecord> examRecords = examRecordMapper.selectList(queryWrapper);

        if (examRecords.isEmpty()) {
            throw new BaseException("你还没有参加此次考试");
        }

        ExamRecord examRecord = examRecords.get(0);
        return examRecord.getTotalScore();
    }

    @Override
    @UserRole(roles = {UserRoleEnum.TEACHER})
    public ExamReport analysisReport(Long examId) {
        //根据examId查询考试
        Exam exam = getById(examId);

        //根据examId查询所有学生错题
        LambdaQueryWrapper<AnswerRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AnswerRecord::getExamId, examId);
        List<AnswerRecord> answerRecords = answerRecordMapper.selectList(queryWrapper);
        queryWrapper.eq(AnswerRecord::getStatus, AnswerStatus.ERROR.getStatus());
        log.info("questionErrors:{}", answerRecords);

        //查询错题对应的学生信息
        List<Long> studentIds = answerRecords.stream().map(AnswerRecord::getUserId).toList();

        if (studentIds.isEmpty()){
            return null;
        }

        //根据examId查询所有考试题目
        LambdaQueryWrapper<Question> questionWrapper = new LambdaQueryWrapper<>();
        questionWrapper.eq(Question::getExamId, examId);
        List<Question> questions = questionMapper.selectList(questionWrapper);
        log.info("questions:{}", questions);


        LambdaQueryWrapper<User> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.in(User::getId, studentIds);
        List<User> users = userMapper.selectList(userWrapper);
        log.info("users:{}", users);

        //查询对应的考试记录
        LambdaQueryWrapper<ExamRecord> recordWrapper = new LambdaQueryWrapper<>();
        recordWrapper.eq(ExamRecord::getExamId, examId);
        List<ExamRecord> examRecords = examRecordMapper.selectList(recordWrapper);
        log.info("examRecords:{}", examRecords);

        //根据错题查询知识点
        HashSet<Long> knowledgeIds = new HashSet<>();
        for (AnswerRecord answerRecord : answerRecords) {
            String[] ids = answerRecord.getKnowledgeIds().split(",");
            knowledgeIds.addAll(Arrays.stream(ids)
                    .map(Long::parseLong)
                    .toList());
        }
        LambdaQueryWrapper<Knowledge> knowledgeWrapper = new LambdaQueryWrapper<>();
        knowledgeWrapper.in(Knowledge::getId, knowledgeIds);
        List<Knowledge> knowledges = knowledgeMapper.selectList(knowledgeWrapper);
        log.info("knowledges:{}", knowledges);

        //交给ai生成考试总结
        summaryExamClient.prompt()
                .user("考试信息" + exam +
                        "，学生信息：" + users +
                        "，错题信息：" + answerRecords +
                        "，考试题目信息：" + questions +
                        "，知识点信息：" + knowledges +
                        "考试记录信息" + examRecords
                )
                .call()
                .content();

        String examReportJson = stringRedisTemplate.opsForValue().get(RedisConstant.EXAM_REPORT_KEY + examId);
        ExamReport examReport = JSON.parseObject(examReportJson, ExamReport.class);

        return examReport;
    }


}